use crate::core::{group::GroupData, item::Item};
use crate::parser::{
    entity::Entity,
    tag::{Tag, TagType},
};

use anyhow::Result;

// parse row result
//
pub enum Row {
    G((usize, GroupData)),
    I((usize, Item)),
}

impl Row {
    pub fn parse(line: &'static str) -> Result<Row> {
        let (entry_str, tag) = Tag::parse(line)?;
        match tag.typ() {
            TagType::GroupData => {
                let (_, group_data) = Entity::parse_group(entry_str)?;
                Ok(Self::G((tag.level(), group_data)))
            }
            TagType::Item => {
                let (_, item) = Entity::parse_item(entry_str)?;
                Ok(Self::I((tag.level(), item)))
            }
        }
    }

    pub fn is_group(&self) -> bool {
        match self {
            Self::G((_, _)) => true,
            _ => false,
        }
    }

    pub fn is_item(&self) -> bool {
        match self {
            Self::I((_, _)) => true,
            _ => false,
        }
    }

    pub fn level(&self) -> usize {
        match self {
            Self::G((level, _)) => *level,
            Self::I((level, _)) => *level,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parse_works() {
        let line = "g[root]";
        let row = Row::parse(line).unwrap();
        match row {
            Row::G((level, group)) => {
                assert_eq!(level, 0);
                assert_eq!(*group.name(), String::from("root"));
            }
            Row::I((_level, _item)) => {
                assert!(false);
            }
        }
        let line = "  g[个人]";
        let row = Row::parse(line).unwrap();
        match row {
            Row::G((level, group)) => {
                assert_eq!(level, 1);
                assert_eq!(*group.name(), String::from("个人"));
            }
            Row::I((_level, _item)) => {
                assert!(false);
            }
        }
        let line = "  i[\"测试标题\", \"jduare\", \"password1\"]";
        let row = Row::parse(line).unwrap();
        match row {
            Row::G((_level, _group)) => {
                assert!(false);
            }
            Row::I((level, item)) => {
                assert_eq!(level, 1);
                assert_eq!(
                    item,
                    Item::new(
                        Some(String::from("测试标题")),
                        Some(String::from("jduare")),
                        Some(String::from("password1")),
                        None,
                        None,
                    ),
                )
            }
        }
    }

    #[test]
    fn is_group_works() {
        let line = "g[root]";
        let row = Row::parse(line).unwrap();
        assert!(row.is_group());
        assert!(!row.is_item());
    }

    #[test]
    fn is_item_works() {
        let line = "  i[\"测试标题\", \"jduare\", \"password1\"]";
        let row = Row::parse(line).unwrap();
        assert!(!row.is_group());
        assert!(row.is_item());
    }

    #[test]
    fn level_test() {
        let line = "g[root]";
        let row = Row::parse(line).unwrap();
        assert_eq!(0, row.level());
        let line = "  i[\"测试标题\", \"jduare\", \"password1\"]";
        let row = Row::parse(line).unwrap();
        assert_eq!(1, row.level());
    }
}
